const fs = require('fs');
const sqlserver = require('mssql');
const config = require('./config');
let addSerial = false
let addFulltext = false
let addInpatientInterval = true
let addOperationInterval = true
let recordslimit = 1000
let index = config.index
let addMoreICDInfo = true
let replaceSingleQuotes = false
// let dbConfigSource = {
//     server: '10.160.12.192',
//     database: 'MR_FS_DB',
//     user: 'sa',
//     password: 'Docimax@123',
//     port: 1433
// };
let dbConfigSource = {
    server: config.dbServer,
    database: 'MR_FS_DB',
    user: 'sa',
    password: 'Docimax@123',
    port: 1433
};
let db = require('./db')

async function getFullText(sid, pool) {
    sql = "select OCRCatalogue,OCRCatalogueID,OCRAllText from VOCR_ResultInfo where Success=1 and OCRImagePriSerialNo='" + sid + "'"
    var r = await pool.request().query(sql);
    let rd = r.recordset
    if (rd === undefined) {
        return []
    }
    return rd
}
async function getPriSerialNo(id, pool) {
    sql = "select PriSerialNo from VMDPMS_MedicalPatientBase where PBaseID='" + id + "'"
    var r = await pool.request().query(sql);
    let rd = r.recordset[0]
    if (rd === undefined) {
        return -1
    }
    return rd['PriSerialNo']
}
async function processMore(id, pool) {
    sql = "select CreateTime ,LastModifyTime from VDoctor where IPB_ID='" + id + "' and DoctorType='编码员'"

    var r = await pool.request().query(sql);
    let rd = r.recordset[0]
    if (rd === undefined) {
        return {}
    }
    let c = rd['CreateTime']
    let l = rd['LastModifyTime']
    return {
        c,
        l
    }

}

async function getInpatientInterval(mrid, admissionDateTime, hospitalizedTimes) {
    let sql = "select DischargeDateTime from VBase where mrid='" + mrid + "' and HospitalizedTimes=" + (hospitalizedTimes--)
    var r = await pool.request().query(sql);
    let rd = r.recordset[0]
    if (rd === undefined) {
        return -1
    }
    return rd['DischargeDateTime'] - admissionDateTime //ms distance
}
async function processDoctor(
    id,
    fkey,
    table,
    typecol,
    valuecol,
    codecol,
    getConnection
) {
    data = [];
    var sql = db.getExtSql(id, fkey, table);
    var r = await getConnection().request().query(sql);

    r.recordset.forEach((d) => {
        let nd = {};
        let key = d[typecol];
        var value = d[valuecol];
        var code = d[codecol];
        nd[key + '.姓名'] = value;
        nd[key + '.编码'] = code;

        data.push(nd);
    });
    return data;
};
function additionalProcessOperate(base, r) {
    r['BeforeOperateTime'] = (r['OperateBeginTime'] - base['AdmissionDateTime']) / 3600000
    r['AfterOperateTime'] = (base['DischargeDateTime'] - r['OperateEndTime']) / 3600000
    r['OperateDuringTime'] = (r['OperateEndTime'] - r['OperateBeginTime']) / 3600000
}
function saveSubItemsCount(r, subItems, key) {
    r[key + 'Count'] = subItems.length
}
let rstr = new RegExp(",", "g");
function processInfo(element) {
    for (const key in element) {
        if (element.hasOwnProperty(key)) {
            let value = element[key];
            if (typeof (value) == 'string')
                element[key] = value.replace(rstr, config.replaceSingleQuotes);
        }
    }
}
async function getExtInfo(element, pool) {

    var id = element["ID"]


    element.Diagnosis = await db.getExt(id, "IPB_ID", "VDiagnosis", () => pool)
    element.Doctor = await processDoctor(id, "IPB_ID", "VDoctor", "DoctorType", "DoctorName", 'DoctorCode', () => pool)
    element.VAllergyDiagnosis = await db.getExt(id, "IPB_ID", "VAllergyDiagnosis", () => pool)
    element.VClinicDiagnosis = await db.getExt(id, "IPB_ID", "VClinicDiagnosis", () => pool)
    element.VContact = await db.getExt(id, "IPB_ID", "VContact", () => pool)
    element.VFee = await db.getExtWithType(id, "IPB_ID", "VFee", "FeeClassName", "FeeValue", [], () => pool)
    element.VICU = await db.getExt(id, "IPB_ID", "VICU", () => pool)
    element.VOperate = await db.getExt(id, "IPB_ID", "VOperate", () => pool, additionalProcessOperate, element)
    element.VSurgery = await db.getExt(id, "IPB_ID", "VSurgery", () => pool, additionalProcessOperate, element)
    element.VTransfer = await db.getExt(id, "IPB_ID", "VTransfer", () => pool)

    await db.processOrderBase(id, "IPB_ID", "VDiagnosis", () => pool, element, 'BaseDiagnosis', 'DiagnosisOrder')
    await db.processOrderBase(id, "IPB_ID", "VOperate", () => pool, element, 'BaseVOperate', 'OperateOrder', additionalProcessOperate)
    await db.processOrderBase(id, "IPB_ID", "VSurgery", () => pool, element, 'BaseVSurgery', 'OperateOrder', additionalProcessOperate)
    if (config.saveSubItemCount) {
        saveSubItemsCount(element, element.Diagnosis, 'Diagnosis')
        saveSubItemsCount(element, element.VAllergyDiagnosis, 'VAllergyDiagnosis')
        saveSubItemsCount(element, element.VClinicDiagnosis, 'VClinicDiagnosis')
        saveSubItemsCount(element, element.VOperate, 'VOperate')
        saveSubItemsCount(element, element.VSurgery, 'VSurgery')
        saveSubItemsCount(element, element.VICU, 'VICU')
        saveSubItemsCount(element, element.VTransfer, 'VTransfer')
        saveSubItemsCount(element, element.VContact, 'VContact')
    }
    let {
        c,
        l
    } = await processMore(id, pool)
    element['CodeTime'] = c
    element['LastModifiedTime'] = l
    let ht = element['HospitalizedTimes'];
    if (ht > 1 && addInpatientInterval) {
        let inpatientInterval = getInpatientInterval(element['mrid'], element['AdmissionDateTime'], ht)
        element['InpatientInterval'] = inpatientInterval / 1000 / 3600 //hours distance
    }
    if (addSerial) {
        let priSerialNo = await getPriSerialNo(id, pool)

        element['PriSerialNo'] = priSerialNo
    }
    if (addFulltext && priSerialNo != undefined && priSerialNo != -1) {
        let r = await getFullText(priSerialNo, pool)
        element['FullText'] = r
    }

    if (addMoreICDInfo) {
        processDocAdditionInfo(element, mappingInfos)
    }
    if (replaceSingleQuotes)
        processInfo(element)
    return element
}
let mappingInfos
const addMoreInfo = require('./addMoreInfo');
function sleep(time) {
    return new Promise(resolve => setTimeout(resolve, time))
}
async function processDocAdditionInfo(doc,
    mappingInfos) {
    try {
        await sleep(10)

        for (let i = 0; i < mappingInfos.length; i++) {
            const minfo = mappingInfos[i];
            await addMoreInfo.processdoc(
                minfo['mapping'],
                doc,
                minfo['docQueryField'],
                minfo['mapSource'],
                minfo['mapTargetList'],
                minfo['docTargetList']
            );
        }
    }
    catch (err) {
        //missingkeys.push(d['_id']);
        fs.appendFileSync("faildprocessDocAdditionInfo.json", "faild:" + doc + JSON.stringify(err))
        console.log("processDocAdditionInfo faild:" + doc + err);
    }
}
let con = undefined
async function getConnection() {
    if (con == undefined) {
        sqlserver.close()
        con = await sqlserver.connect(dbConfigSource);
    }
    return con;
}

async function readData(strsql) {
    var start = new Date();
    let data = [];

    try {
        pool = await getConnection();
        let rs = await pool.request().query(strsql);
        console.log(rs);
        for (let i = 0; i < rs.recordset.length; i++) {
            let element = rs.recordset[i]
            let d = await getExtInfo(element, pool)
            data.push(d);
            console.log(i / rs.recordset.length)
        }

    } catch (error) {
        console.log(error);
    } finally {
        //await pool.close();
    }
    await pool.close();

    //console.log(JSON.stringify(data));
    //return JSON.stringify(data)
    console.log(new Date() - start);
    fs.writeFileSync(".\\data.json", JSON.stringify(data))
    let spend = new Date() - start;
    console.log(spend);
}
var es = require('./es')
//process will continue run
translog = [] //normal process log
exceptionlog = [] //exception log
async function getData(strsql, pool) {
    let data = [];
    try {
        if (pool == undefined)
            pool = await getConnection()
        let rs = await pool.request().query(strsql);
        //console.log(rs);
        for (let i = 0; i < rs.recordset.length; i++) {
            let element = rs.recordset[i]
            let d = await getExtInfo(element, pool)
            data.push(d);
            console.log(i / rs.recordset.length)
        }
        return data
    } catch (error) {
        console.log(error);
    } finally {
        //await pool.close();
    }

}
async function importdata(data, successFile, faildFile, update = false) {

    for (let i = 0; i < data.length; i++) {
        try {
            if (update) {
                let exist = await es.getDocumentById(index, data[i]['ID'])
                if (exist !== undefined) {
                    console.log('delete doc')
                    console.log(data[i]['ID'])
                    await es.deleteDocument(index, data[i]['ID'])

                }
            }
            //fs.appendFileSync(".\\process.json", "import:" + data[i]['ID'])

            let r = await es.addDocument(index, data[i]['ID'], data[i])
            //fs.appendFileSync(".\\dailyprocess.json", "import success:" + data[i]['ID'])
            fs.appendFileSync(successFile, data[i]['ID'] + ',')
            console.log(i / data.length);
        }
        catch {
            fs.appendFileSync(faildFile, data[i]['ID'] + ',')
        }
    }

}
async function importdataBulk(data) {
    if (data.length === 0) return
    let ids = []
    for (let i = 0; i < data.length; i++) {
        ids.push(data[i]['ID'])
    }
    try {
        //await es.deleteDocumentBulk(index, ids, 'ID')
        await es.addDocumentBulk(index, data, 'ID')
        fs.appendFileSync(".\\success.json", JSON.stringify(ids))
    } catch (err) {
        fs.appendFileSync(".\\faild.json", JSON.stringify(ids))

    }

}
function getDateString(d) {
    let s = d.getFullYear().toString() + "-" +
        (d.getMonth() + 1).toString() + "-" +
        d.getDate().toString()
    return s
}

async function trandData(start, end, timeinterval) {
    console.log(start);
    console.log(end);
    var s = new Date();
    pool = await getConnection();
    mappingInfos = await addMoreInfo.getMappingInfos(pool)
    fs.writeFileSync(".\\success.json", '')
    fs.writeFileSync(".\\faild.json", '')
    for (let d = start; d < end; d.addDays(timeinterval)) {
        try {
            console.log('process ' + getDateString(d));
            let xd = new Date(d)
            let sql = "select * from vbase where DischargeDateTime>='" + getDateString(d) + "' and DischargeDateTime<'" + getDateString(xd.addDays(timeinterval)) + "'"
            console.log(sql);
            let data = await getData(sql, pool)
            console.log(data.length);
            await importdataBulk(data)
            console.log('import' + data.length);
            //await importdata(data, true)
        } catch (err) {
            console.log(err);
            fs.appendFileSync(".\\exception.json", JSON.stringify(err))
        }

    }
    await pool.close();
    con = undefined
    let spend = new Date() - s;
    console.log('spend:' + spend.toString());
}



async function trandNewData(start, end, timeinterval) {
    console.log(start);
    var s = new Date();
    pool = await getConnection();
    console.log(pool)
    mappingInfos = await addMoreInfo.getMappingInfos(pool)
    let dataPreStr = s.getFullYear().toString() + (s.getMonth() + 1).toString + s.getDay().toString() + '_' + s.getHours().toString() + s.getMinutes().toString() + s.getSeconds().toString()
    fs.writeFileSync(".\\" + dataPreStr + ".success.json", '')
    fs.writeFileSync(".\\" + dataPreStr + ".faild.json", '')
    for (let d = start; d < end; d.addDays(timeinterval)) {
        try {
            console.log('process ' + getDateString(d));
            let xd = new Date(d)
            let sql = "select * from vbase where LastModifyTime>='" + getDateString(d) + "' and LastModifyTime<'" + getDateString(xd.addDays(timeinterval)) + "'"
            console.log(sql);
            fs.appendFileSync(".\\" + dataPreStr + "sql.json", sql)
            let data = await getData(sql, pool)
            if (data !== undefined && data.length > 0) {
                console.log('import' + data.length);
                await importdata(data, ".\\" + dataPreStr + ".success.json", ".\\" + dataPreStr + ".faild.json", true)
            }
        } catch (err) {
            console.log(err);
            fs.appendFileSync(".\\dailyexception.json", JSON.stringify(err))
        }
    }
    await pool.close();
    con = undefined
    let spend = new Date() - s;
    console.log('spend:' + spend.toString());
}
module.exports.TarnsNew = (backDays) => {
    let start = Date.now()
    start = start - (backDays * 24 * 3600)
    trandNewData(new Date(start), new Date(Date.now()), 1)
}
async function tarnsRecentMonth(months) {
    let start = new Date()
    let targetDay = 1
    let targetMonth = start.getMonth() + 1
    let targetYear = start.getFullYear()

    if (targetMonth > months) {
        targetMonth -= months
    }
    else {
        targetMonth += (12 - months)
        targetYear -= 1
    }
    target = new Date(targetYear, targetMonth, targetDay)
    await trandData(target, new Date(Date.now()), 10)
}
//module.exports.TarnsRecentMonth = tarnsRecentMonth
//下面是导入数据的语句，打开是导入全部数据，执行过一次以后关闭
trandData(new Date('1900/1/1'), new Date('2021/1/1'), 10)

//trandNewData(new Date('2020/3/11'), new Date('2020/3/13'), 1)